from flask import Blueprint, request, render_template
from flask_apscheduler.utils import job_to_dict
from applications.common.utils.rights import authorize
from applications.common.utils.http import table_api, fail_api, success_api
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.date import DateTrigger
from flask import current_app
from datetime import datetime
import os
from flask import jsonify
import importlib.util
import inspect
try:
    # 如果根目录下tasks目录不存在，则动态创建
    if not os.path.exists('tasks'):
        os.makedirs('tasks')    
    import tasks.task_methods as tasks
except ImportError as e:
    pass    
bp = Blueprint('adminTask', __name__, url_prefix='/task')

def get_scheduler():
    return current_app.config.get('SCHEDULER')


# 获取tasks目录下的所有模块名称（排除__init__.py）
def get_module_names(directory):
    module_names = []
    for filename in os.listdir(directory):
        if filename.endswith('.py') and filename != '__init__.py' and filename != 'task_methods.py':
            module_name = filename[:-3]  # 去掉文件扩展名
            module_names.append(module_name)
    return module_names

# 动态加载模块
def load_modules_from_directory(directory):
    modules = {}
    for module_name in get_module_names(directory):
        module_path = os.path.join(directory, f"{module_name}.py")
        spec = importlib.util.spec_from_file_location(module_name, module_path)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        modules[module_name] = module
    return modules

# 获取模块中的所有内容,添加保存到新的task_methods模块中
def get_module_contents(modules):
    task_methods_path = './tasks/task_methods.py'
    task_methods_spec = importlib.util.spec_from_file_location("task_methods", task_methods_path) # 获取模块名和路径
    task_methods = importlib.util.module_from_spec(task_methods_spec) # 动态加载模块    
    task_methods_spec.loader.exec_module(task_methods)  
    return task_methods 

# 获取模块中的所有函数, 返回字典
# {
#     'module_name': [('function_name', function), ...],
#     ...
# } 
def get_module_methods(modules):
    methods = {}
    for module_name, module in modules.items():
        methods[module_name] = inspect.getmembers(module, inspect.isfunction)
    return methods

# 执行指定模块中的函数
def execute_task(task_name, a, b):
    if task_name in globals():
        task_func = globals()[task_name]
        task_func(a, b)
    else:
        print(f"任务 {task_name} 不存在")

# 获取任务列表
def task_lists(): # 返回为列表['task1', 'task2']
    # 加载模块
    directory_path = './tasks'  # 模块文件目录路径
    modules = load_modules_from_directory(directory_path)
    methods = get_module_methods(modules)
    task_lists=[]
    task_methods_path = './tasks/task_methods.py'
    # 清空task_methods.py文件内容
    with open(task_methods_path, 'w', encoding='utf-8') as f:
        pass    
    for module_name, method_list in methods.items():
        task_lists.append(module_name)
        # 将模块名module_name中的函数添加到task_methods.py中
        with open(task_methods_path, 'a', encoding='utf-8') as f:
            # 写入格式 from .{module_name} import {function_name}
            for method in method_list:
                f.write(f"from .{module_name} import {method[0]}\n")    
    # 判断task_lists中是否为空值
    if task_lists == []:
        task_lists.append('无')
    return task_lists # 返回为列表['task1', 'task2']    


@bp.get('/')
@authorize("system:task:main", log=True)
def main():
    return render_template('system/task/main.html')

@bp.route('/data', methods=['GET'])
@authorize("system:task:main", log=True)
def get_task():
    scheduler = get_scheduler()
    jobs = scheduler.get_jobs()
    jobs_list = [job_to_dict(job) for job in jobs]
    return table_api(data=jobs_list, count=len(jobs_list))

@bp.route('/query', methods=['POST','GET'])
@authorize("system:task:main", log=True)
def query():
    if request.method == 'GET':
        selectname = request.args.get('selectname')
    if request.method == 'POST':
        data = request.get_json()
        selectname = data.get('selectname')
    # 查询参数构造
    scheduler = get_scheduler()
    jobs = scheduler.get_jobs()
    jobs_list = [job_to_dict(job) for job in jobs]
    # 模糊查找jobs_list中id、name包含selectname的元素
    if selectname:
        jobs_list = [job for job in jobs_list if selectname.lower() in job['id'].lower() or selectname.lower() in job['name'].lower()]
    # print(data)
    # 返回api
    return table_api(data=jobs_list, count=len(jobs_list))

@bp.get('/add')
@authorize("system:task:add", log=True)
def add():
    return render_template('system/task/add.html', task_list=task_lists())

@bp.post('/save')
@authorize("system:task:add", log=True)
def save():
    data = request.json
    _id = data.get("id") # 任务id
    name = data.get("name") # 任务名称
    type = data.get("type") # 任务类型
    functions = data.get("functions") # 任务函数
    datetime = data.get("datetime") # 触发时间
    interval = data.get("interval") # 间隔时间
    cron = data.get("cron") # cron表达式

    # Validate function existence
    if not hasattr(tasks, functions):
        return fail_api(msg="任务函数不存在")
    func = getattr(tasks, functions)
    # Define job parameters
    job_params = {
        'func': func,
        'id': _id,
        'name': name,
        'args': (_id, name),
        'replace_existing': True
    }

    if type == 'date':
        # Use DateTrigger for date type tasks
        job_params.update({
            'trigger': DateTrigger(run_date=datetime),
            'value': datetime
        })
        
    elif type == 'interval':
        if not interval:
            return fail_api(msg="缺少间隔时间参数")
        # IntervalTrigger expects numerical values for the interval
        try:
            interval_seconds = int(interval)
        except ValueError:
            return fail_api(msg="间隔时间格式错误")
        job_params.update({
            'trigger': IntervalTrigger(seconds=interval_seconds)
        })
    elif type == 'cron':
        if not cron:
            return fail_api(msg="缺少 Cron 表达式参数")
        try:
            # 这里可以添加对 cron 表达式格式的 validation
            job_params.update({
                'trigger': CronTrigger.from_crontab(cron)
            })
        except ValueError as e:
            return fail_api(msg=f"Cron 表达式错误: {str(e)}")
    else:
        return fail_api(msg="不支持的触发器类型")

    # Get scheduler instance
    scheduler = get_scheduler()
    # Add job to the scheduler
    scheduler.add_job(**job_params)
    return success_api()

@bp.put('/update')
@authorize("system:task:add", log=True)
def update():
    data = request.json
    _id = data.get("id")
    name = data.get("name")
    type = data.get("type")
    functions = data.get("functions")
    datetime = data.get("datetime")
    interval = data.get("interval")
    cron = data.get("cron")

    # Validate function existence
    if not hasattr(tasks, functions):
        return fail_api(msg="任务函数不存在")
    func = getattr(tasks, functions)

    # Define job parameters
    job_params = {
        'func': func,
        'id': _id,
        'name': name,
        'args': (_id, name),
        'replace_existing': True
    }

    if type == 'date':
        # Use DateTrigger for date type tasks
        job_params.update({
            'trigger': DateTrigger(run_date=datetime),
            'value': datetime
        })
        
    elif type == 'interval':
        if not interval:
            return fail_api(msg="缺少间隔时间参数")
        # IntervalTrigger expects numerical values for the interval
        try:
            interval_seconds = int(interval)
        except ValueError:
            return fail_api(msg="间隔时间格式错误")
        job_params.update({
            'trigger': IntervalTrigger(seconds=interval_seconds)
        })
    elif type == 'cron':
        if not cron:
            return fail_api(msg="缺少 Cron 表达式参数")
        # CronTrigger expects a cron expression
        job_params.update({
            'trigger': CronTrigger.from_crontab(cron)
        })
    else:
        return fail_api(msg="不支持的触发器类型")

    # Get scheduler instance
    scheduler = get_scheduler()
    # Add job to the scheduler
    scheduler.add_job(**job_params)
    return success_api()

@bp.get('/edit/<string:_id>')
@authorize("system:task:edit", log=True)
def edit(_id=""):
    scheduler = get_scheduler()
    job = scheduler.get_job(str(_id))
    if not job:
        return fail_api(msg="任务不存在")
    
    job_dict = job_to_dict(job)
    functions = job_dict['func'].split(':')[1]
    job_dict['functions'] = functions

    return render_template('system/task/edit.html', task_list=task_lists(), job=job_dict)

@bp.put('/enable')
def enable():
    _id = request.json.get('id')
    if _id:
        scheduler = get_scheduler()
        job = scheduler.get_job(str(_id))
        print(job)
        scheduler.resume_job(str(_id))
        return success_api(msg="启动成功")
    return fail_api(msg="数据错误")

@bp.put('/disable')
def dis_enable():
    _id = request.json.get('id')
    if _id:
        scheduler = get_scheduler()
        job = scheduler.get_job(str(_id))
        print(job)
        scheduler.pause_job(str(_id))
        return success_api(msg="暂停成功")
    return fail_api(msg="数据错误")

@bp.delete('/remove/<string:_id>')
@authorize("system:task:remove", log=True)
def remove_job(_id):
    scheduler = get_scheduler()
    scheduler.remove_job(str(_id))
    return success_api(msg="删除成功")